/* LEDC（LED 控制器）渐变示例

   本示例代码属于公有领域（或根据您的选择采用 CC0 许可）。

   除非适用法律要求或书面同意，
   否则本软件按“原样”分发，不附带任何明示或暗示的担保。
*/
#include <stdio.h>
#include "driver/ledc.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_random.h"
#include <math.h>
#include "driver/gpio.h"
#include "esp_sleep.h"
/*
 * 关于本示例
 *
 * 1. 首先初始化 LEDC 模块：
 *    a. 先设置 LEDC 的定时器，这决定了 PWM 的频率和分辨率。
 *    b. 然后设置你想使用的 LEDC 通道，并与某个定时器绑定。
 *
 * 2. 你需要先安装默认的渐变函数，然后才能使用渐变相关 API。
 *
 * 3. 你也可以直接设置目标占空比而不使用渐变。
 *
 * 4. 在 ESP32 上，GPIO18/19/4/5 用作 LEDC 输出：
 *              GPIO18/19 属于高速通道组
 *              GPIO4/5 属于低速通道组
 *
 *    在其他芯片上，GPIO8/9/4/5 用作 LEDC 输出，且都属于低速通道组。
 *
 * 5. 所有 LEDC 输出会重复改变占空比。
 *
 */
#define LEDC_LS_TIMER_0 LEDC_TIMER_0
#define LEDC_LS_TIMER_1 LEDC_TIMER_1
#define LEDC_LS_TIMER_2 LEDC_TIMER_2
#define LEDC_LS_MODE LEDC_LOW_SPEED_MODE
#define LEDC_LS_CH0_GPIO (1) // GPIO 5 用于粉光
#define LEDC_LS_CH0_CHANNEL LEDC_CHANNEL_0
#define LEDC_LS_CH1_GPIO (2) // GPIO 2 用于粉光
#define LEDC_LS_CH1_CHANNEL LEDC_CHANNEL_1
#define LEDC_LS_CH2_GPIO (3) // GPIO 3 用于橙光
#define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2
#define LEDC_LS_CH3_GPIO (4) // GPIO 9 用于橙光
#define LEDC_LS_CH3_CHANNEL LEDC_CHANNEL_3
#define LEDC_LS_CH4_GPIO (5) // GPIO 10 用于白光
#define LEDC_LS_CH4_CHANNEL LEDC_CHANNEL_4
#define BUTTON_GPIO (0)         // 按钮
#define ESP_INTR_FLAG_DEFAULT 0 // 默认中断标志
#define LEDC_TEST_CH_NUM (5)    // LEDC 通道数量
#define LEDC_TEST_FADE_TIME (3000)
#define DEBOUNCE_TIME_MS 50         // 去抖动时间
volatile bool button_event = false; // 按钮事件标志
static const char *TAG = "led_fade";
static int steps = 100;
static int current_step_1, current_step_2, current_step_3, current_step_4, current_step_no_1, current_step_no_2, current_step_no_3; // 用来记录定时器调用次数
esp_timer_handle_t fade_timer_1;
esp_timer_handle_t fade_timer_2;
esp_timer_handle_t fade_timer_3;
esp_timer_handle_t fade_timer_4;
bool fade_down_red = true;
bool fade_down_white = true;
bool fade_down_orange = true;
float last_value_red = 0;
float last_value_white = 0;
float last_value_orange = 0;
struct LEDC_PWM{
    int LEDC_MAX; // LED 最大亮度
    int LEDC_MIN; // LED 最小亮度
}; 
struct LEDC_PWM LEDC_PWM_callback = {100, 50}; // LED粉光
struct LEDC_PWM LEDC_PWM_orange = {100, 0}; // LED橙光
struct LEDC_PWM LEDC_PWM_white = {100, 0}; // LED白光
typedef enum
{
    STATE_OFF,     // 关闭状态
    STATE_FADE_IN, // 开机状态
    STATE_HOLD_ON, // 渐变保持状态
    STATE_FADE_OUT // 渐变关闭状态（目前用不到）
} light_state_t;
typedef enum
{
    Phase_1,
    Phase_2,
    Phase_3,
} led_no;
led_no Phase = Phase_1; // 灯泡的状态
light_state_t is_power_on = STATE_FADE_IN;
/*
 * 为 LED 控制器的每个通道准备独立配置，选择：
 * - 控制器通道号
 * - 输出占空比，初始设为 0
 * - 连接 LED 的 GPIO 编号
 * - 速度模式，高速或低速
 * - 服务该通道的定时器
 *   注意：如果不同通道共用一个定时器，
 *         则这些通道的频率和位宽将相同
 */

ledc_channel_config_t ledc_channel[LEDC_TEST_CH_NUM] = {
    {.channel = LEDC_LS_CH0_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_LS_CH0_GPIO,
     .speed_mode = LEDC_LS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_LS_TIMER_0,
     .flags.output_invert = 0},

    {.channel = LEDC_LS_CH1_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_LS_CH1_GPIO,
     .speed_mode = LEDC_LS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_LS_TIMER_0,
     .flags.output_invert = 0},

    {.channel = LEDC_LS_CH2_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_LS_CH2_GPIO,
     .speed_mode = LEDC_LS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_LS_TIMER_1,
     .flags.output_invert = 0},

    {.channel = LEDC_LS_CH3_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_LS_CH3_GPIO,
     .speed_mode = LEDC_LS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_LS_TIMER_1,
     .flags.output_invert = 0},

    {.channel = LEDC_LS_CH4_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_LS_CH4_GPIO,
     .speed_mode = LEDC_LS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_LS_TIMER_2,
     .flags.output_invert = 0},
};
void button_pressed_callback(void)
{
    is_power_on = STATE_OFF; // 设置电源状态为关闭
    ESP_LOGI(TAG, "按钮被按下（高电平触发）！");
    esp_timer_stop(fade_timer_1);
    esp_timer_stop(fade_timer_2);
    esp_timer_stop(fade_timer_3);
    current_step_no_1 = current_step_1; // 重置当前步骤
    current_step_no_2 = current_step_2; // 重置当前步骤
    current_step_no_3 = current_step_3; // 重置当前步骤
    current_step_1 = 0;                 // 重置当前步骤
    current_step_2 = 0;                 // 重置当前步骤
    current_step_3 = 0;                 // 重置当前步骤
    esp_timer_start_periodic(fade_timer_1, (uint64_t)((3 * 1000000) / steps));
    esp_timer_start_periodic(fade_timer_2, (uint64_t)((3 * 1000000) / steps));
    // esp_timer_start_periodic(fade_timer_3, (uint64_t)((1 * 1000000) / steps));
    esp_timer_start_periodic(fade_timer_4, 10000); // 10ms
    ESP_LOGI(TAG, "配置完成，进入深度睡眠！");
    gpio_isr_handler_remove(BUTTON_GPIO);
    gpio_uninstall_isr_service();
    esp_sleep_enable_gpio_wakeup(); // 开启 GPIO 唤醒总开关
    esp_deep_sleep_enable_gpio_wakeup(1ULL << BUTTON_GPIO, ESP_GPIO_WAKEUP_GPIO_HIGH);

    vTaskDelay(pdMS_TO_TICKS(3000)); // 稍微延迟，确保日志输出完成
    esp_deep_sleep_start();          // 启动深度睡眠
}
static void IRAM_ATTR vibration_isr_handler(void *arg)
{
    gpio_isr_handler_remove(BUTTON_GPIO); // 禁用中断
    button_event = true;                  // 设置标志
}
void system_off(void)
{
    // 配置按钮 GPIO
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_HIGH_LEVEL,   // 上升沿触发（按下）
        .mode = GPIO_MODE_INPUT,             // 输入模式
        .pin_bit_mask = 1ULL << BUTTON_GPIO, // GPIO0
        .pull_up_en = GPIO_PULLUP_DISABLE,   // 不使能内部上拉
        .pull_down_en = GPIO_PULLDOWN_ENABLE // 外部已下拉
    };
    gpio_config(&io_conf);
    // esp_deep_sleep_enable_gpio_wakeup(1ULL << BUTTON_GPIO, ESP_GPIO_WAKEUP_GPIO_HIGH);
    //  安装 GPIO 中断服务
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    gpio_isr_handler_add(BUTTON_GPIO, vibration_isr_handler, NULL);

    ESP_LOGI(TAG, "等待按钮高电平触发...");
}
int ledc_calc_duty(int duty_cycle)
{
    return (duty_cycle * ((1 << 13) - 1)) / 100; // 将百分比转换为实际占空比
}
// 计算当前的百分比，然后发送给上面ledc_calc_duty，就变成实际的占空比给灯泡
float linear_fade(int LED_MAX, int LED_MIN, int step, int total_steps)
{
    return LED_MAX + ((LED_MIN - LED_MAX) * step) / total_steps;
}
// 随机数
float random_range(float min, float max, float *last_value)
{
    float new_value;
    float epsilon = 0.5;
    do
    {
        uint32_t rand_val = esp_random();
        float normalized = rand_val / (float)UINT32_MAX;
        new_value = min + normalized * (max - min);
    } while (fabs(new_value - *last_value) == epsilon);
    *last_value = new_value;
    return new_value;
}
void ledc_gpio(void)
{
    /*
     * 准备并设置 LED 控制器将使用的定时器配置
     */
    ledc_timer_config_t ledc_timer_0 = {
        .duty_resolution = LEDC_TIMER_13_BIT, // PWM 分辨率
        .freq_hz = 5000,                      // PWM 信号频率
        .speed_mode = LEDC_LS_MODE,           // 定时器模式
        .timer_num = LEDC_LS_TIMER_0,         // 定时器编号
        .clk_cfg = LEDC_AUTO_CLK,             // 自动选择时钟源
    };
    ledc_timer_config_t ledc_timer_1 = {
        .duty_resolution = LEDC_TIMER_13_BIT, // PWM 分辨率
        .freq_hz = 5000,                      // PWM 信号频率
        .speed_mode = LEDC_LS_MODE,           // 定时器模式
        .timer_num = LEDC_LS_TIMER_1,         // 定时器编号
        .clk_cfg = LEDC_AUTO_CLK,             // 自动选择时钟源
    };
    ledc_timer_config_t ledc_timer_2 = {
        .duty_resolution = LEDC_TIMER_13_BIT, // PWM 分辨率
        .freq_hz = 5000,                      // PWM 信号频率
        .speed_mode = LEDC_LS_MODE,           // 定时器模式
        .timer_num = LEDC_LS_TIMER_2,         // 定时器编号
        .clk_cfg = LEDC_AUTO_CLK,             // 自动选择时钟源
    };
    // 为低速通道设置定时器 1 的配置
    ledc_timer_config(&ledc_timer_0);
    ledc_timer_config(&ledc_timer_1);
    ledc_timer_config(&ledc_timer_2);
    for (int i = 0; i < LEDC_TEST_CH_NUM; i++)
    {
        ledc_channel_config(&ledc_channel[i]);
    }
}
// 粉灯 粉光
void fade_timer_callback_1(void *arg)
{
    if (current_step_1 > steps && is_power_on == STATE_HOLD_ON)
    {
        ESP_LOGI(TAG, "粉光开始反转");
        fade_down_red = !fade_down_red;
        current_step_1 = 0;
        esp_timer_stop(fade_timer_1);
        esp_timer_start_periodic(fade_timer_1, (uint64_t)((random_range(2, 4, &last_value_red) * 1000000) / steps));
        return;
    }
    // 从100%线性变到50%
    
    int duty_red = 0;
    if (is_power_on == STATE_HOLD_ON)
    {
        ESP_LOGI(TAG, "渐变状态：当前步数: %d, duty_red: %d", current_step_1, duty_red);
        duty_red = fade_down_red ? linear_fade(LEDC_PWM_callback.LEDC_MAX, LEDC_PWM_callback.LEDC_MIN, current_step_1, steps) : linear_fade(LEDC_PWM_callback.LEDC_MIN, LEDC_PWM_callback.LEDC_MAX, current_step_1, steps);
    }
    else if (is_power_on == STATE_FADE_IN)
    {
        ESP_LOGI(TAG, "开机状态：当前步数: %d, duty_red: %d", current_step_1, duty_red);
        duty_red = linear_fade(100, 50, current_step_1, steps);
    }
    else if (is_power_on == STATE_OFF && current_step_no_1 != 0)
    {
        printf("关机：当前步数: %d, duty_red: %d\n", current_step_1, current_step_no_1);
        duty_red = current_step_no_1 * (steps - current_step_1) / steps;
    }
    ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[0].channel, ledc_calc_duty(duty_red));
    ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[0].channel);
    ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[1].channel, ledc_calc_duty(duty_red));
    ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[1].channel);

    current_step_1++;
}
// 橙灯 橙光
void fade_timer_callback_2(void *arg)
{
    if (current_step_2 > steps && is_power_on == STATE_HOLD_ON)
    {
        ESP_LOGI(TAG, "橙光开始反转");
        fade_down_orange = !fade_down_orange;
        current_step_2 = 0;
        esp_timer_stop(fade_timer_2);
        esp_timer_start_periodic(fade_timer_2, (uint64_t)((random_range(1.5, 3, &last_value_orange) * 1000000) / steps));
        return;
    }
    int duty_orange = 0;
    if (is_power_on == STATE_HOLD_ON)
    {
        ESP_LOGI(TAG, "渐变状态：当前步数:当前步数: %d, duty_orange: %d", current_step_2, duty_orange);
        duty_orange = fade_down_orange ? linear_fade(LEDC_PWM_orange.LEDC_MAX, LEDC_PWM_orange.LEDC_MIN, current_step_2, steps) : linear_fade(LEDC_PWM_orange.LEDC_MIN, LEDC_PWM_orange.LEDC_MAX, current_step_2, steps);
    }
    else if (is_power_on == STATE_FADE_IN)
    {
        ESP_LOGI(TAG, "开机状态：当前步数: %d, duty_orange: %d", current_step_2, duty_orange);
        duty_orange = linear_fade(100, 0, current_step_2, steps);
    }
    else if (is_power_on == STATE_OFF && current_step_no_2 != 0)
    {
        printf("关机：当前步数: %d, duty_orange: %d\n", current_step_2, current_step_no_2);
        duty_orange = linear_fade(current_step_no_2, 0, current_step_2, steps);
    }

    ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[2].channel, ledc_calc_duty(duty_orange));
    ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[2].channel);
    ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[3].channel, ledc_calc_duty(duty_orange));
    ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[3].channel);

    current_step_2++;
}

// 黄灯，白光
void fade_timer_callback_3(void *arg)
{
    int duty_white = 0;
    if (current_step_3 > steps && is_power_on == STATE_HOLD_ON)
    {
        ESP_LOGI(TAG, "白光开始反转");
        fade_down_white = !fade_down_white;
        current_step_3 = 0;
        esp_timer_stop(fade_timer_3);
        esp_timer_start_periodic(fade_timer_3, (uint64_t)((random_range(1.5, 4, &last_value_white) * 1000000) / steps));
        return;
    }
    if (is_power_on == STATE_FADE_IN) // 开机渐变
    {
        duty_white = linear_fade(100, 0, current_step_3, steps);
    }
    else if (is_power_on == STATE_HOLD_ON) // 渐变保持状态
    {
        duty_white = fade_down_white ? linear_fade(LEDC_PWM_white.LEDC_MIN, LEDC_PWM_white.LEDC_MAX, current_step_3, steps) : linear_fade(LEDC_PWM_white.LEDC_MAX, LEDC_PWM_white.LEDC_MIN, current_step_3, steps);
    }
    ESP_LOGI(TAG, "当前步数: %d, duty_white: %d", current_step_3, duty_white);
    ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel, ledc_calc_duty(duty_white));
    ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel);
    current_step_3++;
}
void fade_timer_callback_on(void *arg)
{

    printf("开机渐变\n");
    ESP_LOGI(TAG, "当前步数: %d,duty_white: %d", current_step_4, current_step_4);
    switch (Phase) // 使用 switch-case 语句来处理不同的步数
    {
    case Phase_1:
        printf("Phase_1: 当前步数: %d\n", current_step_4);
        ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel, ledc_calc_duty(current_step_4));
        ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel);
        current_step_4++;
        if (current_step_4 == 100)
        {
            current_step_4 = 0; // 重置步数
            Phase = Phase_2;    // 切换到下一个阶段
            printf("Phase_1 完成，切换到 Phase_2\n");
            return; // 直接返回，避免继续执行后续代码
        }
        break;
    case Phase_2:
        printf("Phase_2: 当前步数: %d\n", current_step_4);
        current_step_4++;
        ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel, ledc_calc_duty(100));
        ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel);
        if (current_step_4 == 50)
        {
            current_step_4 = 100; // 重置步数
            Phase = Phase_3;      // 切换到下一个阶段
            printf("Phase_1 完成，切换到 Phase_2\n");
            return; // 直接返回，避免继续执行后续代码
        }
        break;
    case Phase_3:
        printf("Phase_3: 当前步数: %d\n", current_step_4);
        ledc_set_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel, ledc_calc_duty(current_step_4));
        ledc_update_duty(LEDC_LOW_SPEED_MODE, ledc_channel[4].channel);
        current_step_4--;
        if (current_step_4 == 0)
        {
            esp_timer_stop(fade_timer_4);
            if (is_power_on == STATE_FADE_IN) // 如果是开机渐变状态
            {
                is_power_on = STATE_HOLD_ON;
                esp_timer_start_periodic(fade_timer_3, (uint64_t)((random_range(2, 4, &last_value_red) * 1000000) / steps));
                system_off(); // 进入深度睡眠的函数，刚好是在灯泡渐变完成后调用
            }
            current_step_4 = 0; // 重置步数
            Phase = Phase_1;    // 切换到下一个阶段
            printf("Phase_3 完成，切换到 Phase_1\n");
            return; // 直接返回，避免继续执行后续代码
        }
        break;

    default:
        break;
    }
}

void esp_timer_led(void)
{
    const esp_timer_create_args_t timer_args_1 = {
        .callback = &fade_timer_callback_1,
        .name = "fade_timer_1"};
    // 创建定时器
    esp_timer_create(&timer_args_1, &fade_timer_1);
    current_step_1 = 0;
    // 创建第二个定时器
    const esp_timer_create_args_t timer_args_2 = {
        .callback = &fade_timer_callback_2,
        .name = "fade_timer_2"};
    esp_timer_create(&timer_args_2, &fade_timer_2);
    current_step_2 = 0;
    const esp_timer_create_args_t timer_args_3 = {
        .callback = &fade_timer_callback_3,
        .name = "fade_timer_3"};
    // 创建定时器
    esp_timer_create(&timer_args_3, &fade_timer_3);
    current_step_3 = 0;

    const esp_timer_create_args_t timer_args_4 = {
        .callback = &fade_timer_callback_on,
        .name = "fade_timer_4"};
    // 创建定时器
    esp_timer_create(&timer_args_4, &fade_timer_4);
    current_step_4 = 0;

    esp_timer_start_periodic(fade_timer_1, (uint64_t)((2.5 * 1000000) / steps));
    esp_timer_start_periodic(fade_timer_2, (uint64_t)((2.5 * 1000000) / steps));
    esp_timer_start_periodic(fade_timer_4, 10000); // 10ms
}
void app_main(void)
{
    ledc_gpio();
    esp_timer_led();
    while (1)
    {
        if (button_event)
        {
            ESP_LOGI(TAG, "按钮事件被触发，处理按钮按下事件...");
            button_event = false;
            if (gpio_get_level(BUTTON_GPIO) == 1)
            {                              // 确认仍是高电平
                button_pressed_callback(); // 执行回调
            }
            // 重新启用中断
            gpio_isr_handler_add(BUTTON_GPIO, vibration_isr_handler, NULL);
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}
